
#include <string.h>
#include <stdlib.h>
#include "cmsis_os2.h"
#include <ctype.h>

#include "CSNetwork-Client.h"
#include "http_client.h"
#include "roarlang.h"
#include "fallback.h"
#define SERVER "http://test.openblock.online/roar_server/"

typedef struct {
    int request_id;
    const char *custom_data;
} request_context_t;
typedef struct{
    char project_id[8];
    char server_sence[8];
    char title[20];
    char* contentType;
    void* data;
}request;

// 辅助函数：将字符转换为十六进制字符串
static void to_hex(char c, char hex[3]) {
    sprintf(hex, "%%%02X", (unsigned char)c);
}

// URL编码函数
static char* url_encode(const char* input) {
    size_t input_len = strlen(input);
    // 估计输出字符串的长度（最坏情况下每个字符都被编码）
    size_t output_len = input_len * 3 + 1; // 每个字符最多占3个字节（%XX）加上一个结束符
    char* output = (char*)malloc(output_len);
    if (!output) {
        return NULL;
    }

    char* write_ptr = output;
    for (size_t i = 0; i < input_len; ++i) {
        unsigned char c = (unsigned char)input[i];
        // 检查字符是否需要编码
        if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
            *write_ptr++ = c;
        } else {
            char hex[3];
            to_hex(c, hex);
            strcpy(write_ptr, hex);
            write_ptr += 3;
        }
    }
    *write_ptr = '\0'; // 添加字符串结束符

    // 调整输出字符串的大小以节省空间（可选）
    output = (char*)realloc(output, strlen(output) + 1);

    return output;
}

static char* copyToHeap(char* original_string){

    // 计算字符串长度（包括终止符 '\0'）
    size_t length = strlen(original_string) + 1;
    
    // 动态分配内存
    char *heap_string = (char *)malloc(length);
    if (heap_string == NULL) {
        printf("Memory allocation failed\n");
        return NULL;
    }
    
    // 将字符串复制到堆内存中
    strcpy(heap_string, original_string);
    return heap_string;
}
// static void response_callback(void *user_data) {
//     AsyncOperation* op = (AsyncOperation*)user_data;
//     request* r =(request*) op->userdata;
//     if(strcmp(r->title,"text/Integer")==0){
//         char* endptr;
//         long long num = strtoll(r->data, &endptr, 10);
//     }
// }
int asyncSendMessageToServer(AsyncOperation* op){
    request* r = op->userdata;
    char url[256] = {0};
    char* title = url_encode(r->title);
    sprintf_s(url,256,"%s%s/%s/msg/%s",SERVER,r->project_id,r->server_sence,title);
    free(title);
    char headers[128] = {0};
    sprintf_s(headers,128,"\r\ncallerfsmid: %d\r\ncallervmid: %d\r\ncallerscene:%s-%s",op->fsmid,op->vmid,PROJECT_ID_STR,SCENE_ID_STR);
    char* response;
    response = http_post_with_headers(url,r->data,r->contentType,headers);
    char contentType[20] = {0};
    lastHeader("Content-Type",contentType,20);
    char vmid_s[4]={0};
    lastHeader("targetvmid",vmid_s,4);
    char fsmid_s[10] = {0};
    lastHeader("targetfsmid",fsmid_s,10);
    uint16_t vmid = atoi(vmid_s);
    uint16_t fsmid = atoi(fsmid_s);
    AsyncMessage aMsg = {0};
    aMsg.msg.type = OB_Message_Type_USERMSG;
    char* title1 = malloc(50);
    lastHeader("title",title1,49);
    aMsg.msg.name = title1;
    //printf("answer:%s title:%s MIME:%s vmid:%d/%s fsmid:%d/%s \r\n",response,title1,contentType,vmid,vmid_s,fsmid,fsmid_s);
    
    free(r->data);
    if(op->vmid!=vmid){
        free(r);
        free(op);
        printf("wrong vmid,task finished.");
        return 1;
    }
    aMsg.fsm = fsmid;
    op->fsmid = fsmid;
    if(strcmp(contentType,"text/Integer")==0){
        char* endptr;
        long long lnum = strtoll(response, &endptr, 10);
        aMsg.msg.arg.integer = lnum;
       aMsg.msg.argType = copyToHeap("Integer");
    }else if(strcmp(contentType,"text/Number")==0){
        char* endptr;
        double dnum = strtod(response, &endptr);
        aMsg.msg.arg.number = dnum;
       aMsg.msg.argType = copyToHeap("Number");
    }else if(strcmp(contentType,"text/Boolean")==0){
        char* endptr;
        long long lnum = strtoll(response, &endptr, 10);
        aMsg.msg.arg.integer = lnum;
       aMsg.msg.argType = copyToHeap("Boolean");
    }else if(strcmp(contentType,"text/Colour")==0){
        char* endptr;
        long long lnum = strtoll(response, &endptr, 16);
        aMsg.msg.arg.integer = lnum;
       aMsg.msg.argType = copyToHeap("Colour");
    }else if(strcmp(contentType,"text/plain")==0){
        aMsg.msg.arg.ptrdiff = (size_t)response;
       aMsg.msg.argType = copyToHeap("String");
    }else{
        printf("unsupported type:%s",contentType);
    }
    printf("aMsg.msg.argType %ld\r\n",aMsg.msg.argType);
    // return 0;
    OB_FSM_post_message_async(op->vm,&aMsg);
    // aMsg = aMsg;
    if(strcmp(contentType,"text/plain")!=0){
        free(response);
    }
    free(op->userdata);
    op->userdata = NULL;
    printf("task finished.\r\n");
    return 0;
}
static inline int min(int a, int b) {
    return (a < b) ? a : b;
}
int _sendMessageToServer(OB_VM* vm,FSM_PTR fsm,char* project_id,char* server_sence,char* title,char* type,void* msg){
    request* r = calloc(1,sizeof(request));
    memcpy(r->project_id,project_id,min(strlen(project_id),8));
    memcpy(r->server_sence,server_sence,min(strlen(server_sence),8));
    memcpy(r->title,title,min(strlen(title),20));
    if(strcmp(type, "Integer")==0){
        char *buffer = (char *) malloc(50);
        // 将整数转换为字符串
        int resultInt = sprintf_s(buffer, sizeof(buffer), "%ld", (long)(msg));
        if (resultInt == -1) {
            buffer[0] = '0';
        }
        r->data = buffer;
        r->contentType = "text/Integer";
    }else if(strcmp(type, "Number")==0){
        char *buffer = (char *) malloc(50);
        // 将整数转换为字符串
        int resultInt = sprintf_s(buffer, sizeof(buffer), "%.17f", (double)(long)(msg));
        if (resultInt == -1) {
            buffer[0] = '0';
        }
        r->data = buffer;
        r->contentType = "text/Number";
    }else if(strcmp(type, "String")==0){
        char *copy = (char *) malloc(strlen((char*)msg) + 1);
        if (copy == NULL) { // 检查是否成功分配内存
            printf("Memory allocation failed\n");
            return 3;
        }
        r->data = copy;
        r->contentType = "text/plain";
    }else if(strcmp(type, "Boolean")==0){
        r->data = msg == 0?"0":"1";
        r->contentType = "text/Boolean";
    }else if(strcmp(type, "Colour")==0){
        char *buffer = (char *) malloc(20);
        // 将整数转换为字符串
        int resultInt = sprintf_s(buffer, sizeof(buffer), "%lX", (long)(msg));
        if (resultInt == -1) {
            buffer[0] = '0';
        }
        r->data = buffer;
        r->contentType = "text/Colour";
    }else if(strcmp(type, "OB_OBJ")==0){
        r->contentType = "application/OB_OBJ";
        free(r);
        return 1;
    }else{
        free(r);
        return 2;
    }
    AsyncOperation op1 = {0}; //calloc(1,sizeof(AsyncOperation));//{0}
    AsyncOperation* op = &op1;
    op->vm = vm;
    op->vmid = VMID(vm);
    op->fsmid = fsm;
    op->func = asyncSendMessageToServer;
    op->userdata = r;
    runAsyncOperation(op);
    // free(op);
    return 0;
}
int _isNetworkMessage(OB_VM* vm,MSG_PTR msg){
    vm = vm;
    printf("isNetworkMessage %d %d",VMID(vm),msg);
    return 0;
}